package GUI.studentGUI;

import java.awt.Font;
import java.awt.SystemColor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.Date;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextArea;
import javax.swing.border.TitledBorder;

import common.Perror;

import GUI.MainGUI;
import controllers.StudentController;
import entities.Answer;
import entities.ComputerizedExam;
import entities.ExamAbstract;
import entities.ExtractedExam;
import entities.Question;
import entities.QuestionPerExam;


/**
 * 
 * the student exam
 *
 */
public class StudentExamined extends JPanel implements ActionListener {
	
	private static final long serialVersionUID = 1L;
	private static final int OPENSCREEN = -1;
	private StudentController StudentCtrl;
	
	private Long durationTime;
	private JLabel lblTime;
	private JLabel lblTimer;
	private JLabel lblQuestion;
	private JButton btnFinish;
	private JButton btnNext;
	private JButton btnPrev;
	private JRadioButton rdbtnAnswer1;
	private JRadioButton rdbtnAnswer2;
	private JRadioButton rdbtnAnswer3;
	private JRadioButton rdbtnAnswer4;

	private JTextArea txtFldQuestion;
	private JTextArea textAreaInstructions;
	private JLabel lblExamInstructions;
	private final ButtonGroup buttonGroup = new ButtonGroup();
	private JTextArea txtAreaQusetionInstructions;
	private JLabel lblInstructions;;

	// all the ingredients for an exam:
	private ArrayList<Integer> rightAnswerPosition;
	private int questionNum; // which screen are we on?
	private ComputerizedExam cptExam;
	private ExtractedExam exm;
	private ArrayList<QuestionPerExam> qstns;
	private ArrayList<Answer> answers; // PrimaryKey of Answer only
	private HashMap<Integer, Integer> markedAns;

	private Date theDate;
/**
 * the student take exam 
 * @param StudentCtrl
 * @param exam
 * @param questions
 * @param rightAnswerPsn
 */
	public StudentExamined(StudentController StudentCtrl, ExtractedExam exam,
			ArrayList<QuestionPerExam> questions,
			ArrayList<Integer> rightAnswerPsn) {
		super();
		this.StudentCtrl = StudentCtrl;
		this.questionNum = OPENSCREEN;
		qstns = new ArrayList<QuestionPerExam>();
		qstns.addAll(questions);
		exm = exam;
		rightAnswerPosition = new ArrayList<Integer>();
		rightAnswerPosition.addAll(rightAnswerPsn);
		durationTime = (exam.getExamExtractDate().getTime() - Calendar.getInstance().getTimeInMillis() + exam.getExamDurationTime().getTime() + exam.getExamExtantionDuration().getTime()) /1000l;
		 
		initialize();
		new Counter().start();
	}

	/**
	 * initializing the GUI
	 */
	private void initialize() {
		Answer nsr = null;
		Question qstn;

		theDate = new Date(Calendar.getInstance().getTimeInMillis());

		setBorder(new TitledBorder(null, " exam: ", TitledBorder.LEADING,
				TitledBorder.TOP, null, null));
		setBackground(SystemColor.activeCaption);
		setBounds(0, 0, MainGUI.setX, MainGUI.setY);
		setLayout(null);
		cptExam = new ComputerizedExam();
		cptExam.setExamCode(exm.getExamCode());
		cptExam.setExamBeginingHour(theDate);

		answers = new ArrayList<Answer>();
		markedAns = new HashMap<Integer, Integer>();

		for (int i = 0; i < (rightAnswerPosition.size()); i++) {
			qstn = qstns.get(i).getQuestion();
			nsr = new Answer(qstn.getqID(), qstn.getSubjectID(), -1);
			markedAns.put(new Integer(i), new Integer(-1));
			answers.add(nsr);
		}

		AddRelevantGUIelements();

	}

	/*
	 * **********************************************************************
	 * GETTERS AND SETTERS *
	 * ***********************************************************************
	 */
	/**
	 * add the question to array
	 * @param questionArr
	 */
	public void setQstnsArray(ArrayList<QuestionPerExam> questionArr) {
		qstns = new ArrayList<QuestionPerExam>();
		qstns.addAll(questionArr);
	}

	public void setExtractedExam(ExtractedExam theExam) {
		exm = theExam;
	}

	public void SETrightAnswerPosition(ArrayList<Integer> rtAnsArr) {
		rightAnswerPosition = new ArrayList<Integer>();
		rightAnswerPosition.addAll(rtAnsArr);
	}

	
/**************************
 * GUI elements getters
 **************************/
	public JLabel GETlblExamInstructions() {
		if (lblExamInstructions == null) {
			lblExamInstructions = new JLabel("Exam instructions:");
			lblExamInstructions.setBounds(10, 32, 147, 28);
		}
		return lblExamInstructions;
	}

	public JButton GETbtnBack() {
		if (btnPrev == null) {
			btnPrev = new JButton("Previous");
			btnPrev.setBounds(10, 447, 89, 42);
			btnPrev.addActionListener(this);
		}
		if (questionNum == OPENSCREEN)
			btnPrev.setEnabled(false); // when this is the first question
										// disable the button
		else
			btnPrev.setEnabled(true); // when this is not the last question
										// enable the button.

		return btnPrev;
	}

	private JTextArea gettxtAreaQuestion() {
		if (txtFldQuestion == null) {
			txtFldQuestion = new JTextArea();
			txtFldQuestion.setBounds(30, 173, 460, 88);
			txtFldQuestion.setColumns(10);
			txtFldQuestion.setEditable(false);
		}
		txtFldQuestion.setText(qstns.get(questionNum).getQuestion().getqText());
		return txtFldQuestion;
	}

	private JTextArea getTextAreaInstructionsOFexam() {
		if (textAreaInstructions == null) {
			textAreaInstructions = new JTextArea();
			textAreaInstructions.setBounds(20, 67, 470, 204);
			textAreaInstructions.setEditable(false);
		}
		textAreaInstructions.setText(exm.getExamStudentInstructions());
		return textAreaInstructions;
	}

	private JTextArea gettxtAreaInstructions() {
		if (txtAreaQusetionInstructions == null) {
			txtAreaQusetionInstructions = new JTextArea();
			txtAreaQusetionInstructions.setBounds(30, 71, 460, 72);
			txtAreaQusetionInstructions.setEditable(false);
		}
		txtAreaQusetionInstructions.setText(qstns.get(questionNum)
				.getQuestion().getqInstructions());
		return txtAreaQusetionInstructions;
	}

	private JLabel getLblInstructions() {
		if (lblInstructions == null) {
			lblInstructions = new JLabel("Instructions:");
			lblInstructions.setBounds(10, 46, 123, 25);
		}
		return lblInstructions;
	}

	private JLabel GETlblTime() {
		if (lblTime == null) {
			lblTime = new JLabel("time:");
			lblTime.setBounds(323, 25, 39, 14);
		}
		return lblTime;
	}

	private JLabel GETlblQuestion() {
		if (lblQuestion == null) {
			lblQuestion = new JLabel("Question:");
			lblQuestion.setBounds(10, 137, 200, 50);
		}
		return lblQuestion;
	}

	private JButton GETbtnFinish() {
		if (btnFinish == null) {
			btnFinish = new JButton("Finish Exam");
			btnFinish.setFont(new Font("Tahoma", Font.BOLD, 13));
			btnFinish.setBounds(384, 446, 106, 42);
			btnFinish.addActionListener(this);
		}
		return btnFinish;
	}

	private JButton GETbtnNext() {
		if (btnNext == null) {
			btnNext = new JButton("Next");
			btnNext.setBounds(109, 447, 89, 42);
			btnNext.addActionListener(this);
		}
		if ((questionNum + 1) == (qstns.size()))
			btnNext.setEnabled(false); // when this is the last question disable
										// the button
		else
			btnNext.setEnabled(true); // when this is not the last question
										// enable the button.
		return btnNext;
	}

	private JRadioButton GETrdbtnAnswer1() {
		if (rdbtnAnswer1 == null) {
			rdbtnAnswer1 = new JRadioButton("answer1");

			rdbtnAnswer1.setMnemonic('1');
			buttonGroup.add(rdbtnAnswer1);
			rdbtnAnswer1.setBounds(30, 272, 460, 34);
			rdbtnAnswer1.addActionListener(this);
		}

		rdbtnAnswer1.setSelected(checkPrevAnswer(1)); // mark as selected if it
														// was previously
														// selected

		rdbtnAnswer1.setText(calcQuestionForOptionNum(1));

		return rdbtnAnswer1;
	}
	

	private JRadioButton GETrdbtnAnswer2() {
		if (rdbtnAnswer2 == null) {
			rdbtnAnswer2 = new JRadioButton("answer2");

			rdbtnAnswer2.setMnemonic('2');
			buttonGroup.add(rdbtnAnswer2);
			rdbtnAnswer2.setBounds(30, 317, 460, 34);

			rdbtnAnswer2.addActionListener(this);
		}

		rdbtnAnswer2.setText(calcQuestionForOptionNum(2));
		rdbtnAnswer2.setSelected(checkPrevAnswer(2)); // mark as selected if it
														// was previously
														// selected

		return rdbtnAnswer2;
	}
	

	private JRadioButton GETrdbtnAnswer3() {
		if (rdbtnAnswer3 == null) {
			rdbtnAnswer3 = new JRadioButton("answer3");

			rdbtnAnswer3.setMnemonic('3');
			buttonGroup.add(rdbtnAnswer3);
			rdbtnAnswer3.setBounds(30, 362, 460, 34);
			rdbtnAnswer3.addActionListener(this);
		}

		rdbtnAnswer3.setText(calcQuestionForOptionNum(3));

		rdbtnAnswer3.setSelected(checkPrevAnswer(3)); // mark as selected if it
														// was previously
														// selected

		return rdbtnAnswer3;
	}
	

	private JRadioButton GETrdbtnAnswer4() {
		if (rdbtnAnswer4 == null) {
			rdbtnAnswer4 = new JRadioButton("answer4");

			rdbtnAnswer4.setMnemonic('4');
			buttonGroup.add(rdbtnAnswer4);
			rdbtnAnswer4.setBounds(30, 406, 460, 34);
			rdbtnAnswer4.addActionListener(this);
		}

		rdbtnAnswer4.setText(calcQuestionForOptionNum(4));

		rdbtnAnswer4.setSelected(checkPrevAnswer(4)); // mark as selected if it
														// was previously
														// selected
		return rdbtnAnswer4;
	}
	

	
	private JLabel GETlblTimer() {
		if (lblTimer == null)
		{
			lblTimer = new JLabel("");
			lblTimer.setBounds(380, 25, 110, 14);
		}
		return lblTimer;
	}

	/**
	 * * this function saves the question data and the students answers. note that
	 * this function gets 'chosenOption': it refers to the random-generated
	 * option number. here we will decode it to the original numbering: 1 is the
	 * right answer, 2 is wrong answer A,and so on.
	 * @param chosenOption
	 */	 
	private void saveData(int chosenOption) {

		int selection = calcOriginalPosionOfSelection(chosenOption);
		answers.get(questionNum).setSelectedAnswer(selection);

		markedAns.put(questionNum, new Integer(chosenOption));

	}
	
	/**
	 * this function calculates the original position of the selection; what the user
	 * sees is in a scrabled order. the function restores the original order (where
	 * 1 is the right answer, 2 is wrong answer number1, and so on) and returns it.
	 * @param selection
	 * @return
	 */
	private int calcOriginalPosionOfSelection(int selection) {
		int temp;
		int rtAnsPos = rightAnswerPosition.get(questionNum);
		temp = ((selection + 4 - rtAnsPos) % 4) + 1;
		return temp;
	}

	
	/**
	 * * this function checks if this question was previously answerd by the user,
	 * and if so it returns 'true', implying that this question should be marked
	 * as selected if the user decides to return to it.
	  * @param selectionNum
	 * 
	 */
	private boolean checkPrevAnswer(int selectionNum) {

		// if the user did this question before
		if ((markedAns.get(questionNum).equals(selectionNum)))
			return true;
		return false;
	}
	
	
/**
 *  Add Relevant GUI elements to screen
 */
	private void AddRelevantGUIelements() {
		add(GETlblTime());
		add(GETbtnNext());
		add(GETbtnBack());
		add(GETlblTimer());		

		if (questionNum == OPENSCREEN) // if we are on the opening screen of the exam
		{
			add(getTextAreaInstructionsOFexam());
			add(GETlblExamInstructions());
			this.repaint();

		} else // if we are on a question
		{
			add(GETlblQuestion());
			add(GETbtnFinish());
			add(GETrdbtnAnswer1());
			add(GETrdbtnAnswer2());
			add(GETrdbtnAnswer3());
			add(GETrdbtnAnswer4());
			add(gettxtAreaQuestion());
			add(gettxtAreaInstructions());
			add(getLblInstructions());
		}
	}

	private void removeRelevantGUIelements() {
		if (questionNum == OPENSCREEN) // if it's the opening screen of the exam
		{
			remove(getTextAreaInstructionsOFexam());
			remove(GETlblExamInstructions());
			this.repaint();
			return;
		}
		// if we are on a question
		remove(GETlblQuestion());
		remove(GETbtnFinish());
		remove(GETbtnNext());
		remove(GETrdbtnAnswer1());
		remove(GETrdbtnAnswer2());
		remove(GETrdbtnAnswer3());
		remove(GETrdbtnAnswer4());
		remove(gettxtAreaQuestion());
		remove(GETbtnBack());
		remove(getLblInstructions());
	}

	/*
	 * public void setQuestionIndex(int index) { questionIndex=index; }
	 */

	@Override
	public void actionPerformed(ActionEvent e) {

		if (e.getSource() == rdbtnAnswer1)
			saveData(1);
		if (e.getSource() == rdbtnAnswer2)
			saveData(2);
		if (e.getSource() == rdbtnAnswer3)
			saveData(3);
		if (e.getSource() == rdbtnAnswer4)
			saveData(4);
		if (e.getSource() == btnFinish) {
			cptExam.setExamFinishStatus(ExamAbstract.STATUS_STUDENT_FINISHED); // set
																				// the
																				// status
			computerizedExamFinishProccess();
		}
		if ((e.getSource() == btnNext) || (e.getSource() == btnPrev)) {
			removeRelevantGUIelements(); // delete all elements from the screen

			if (e.getSource() == btnNext)
				++questionNum;

			else
				--questionNum;

			AddRelevantGUIelements(); // show all relevant elements in the
										// 'next'
										// screen
			if ((questionNum != OPENSCREEN)
					&& (markedAns.get(questionNum).equals(-1)))
				buttonGroup.clearSelection();
			this.repaint();

		}
	}

	/**
	 * *
	 *  FUNCTION: calcQuestionForOptionNum this function calculates and returns
	 * the text that would be shown as optional answer that has the number
	 * 'optionNum' in the computerized exam, in question number 'QuestionNum'.
	 * @param optionNum
	 * 
	 */
	public String calcQuestionForOptionNum(int optionNum) {
		int temp;
		int rtAnsPos = rightAnswerPosition.get(questionNum);
		Question qstn = qstns.get(questionNum).getQuestion(); // get the
																// question
		String str = null;

		temp = (optionNum + 4 - rtAnsPos) % 4;

		switch (temp) {
		case 0:
			str = new String(qstn.getCorrectAns());
			break;

		case 1:
			str = new String(qstn.getAnswerA());
			break;

		case 2:
			str = new String(qstn.getAnswerB());
			break;

		case 3:
			str = new String(qstn.getAnswerC());
			break;

		}

		return str;
	}
/**
 * computerized Exam Finish Process  
 */
	public void computerizedExamFinishProccess() {
		cptExam.setExamApproved(false); // mark the exam as unApproved by
										// lecturer.

		Date theDate = new Date(Calendar.getInstance().getTimeInMillis()); // save
																			// ending
																			// time
		cptExam.setExamEndingHour(theDate);
		cptExam.setAnswers(answers);
		StudentCtrl.finishExam(cptExam);
	}

	public ArrayList<QuestionPerExam> getQuestions() {
		return qstns;
	}

	public void finishExamByTimer() {
		cptExam.setExamFinishStatus(ExamAbstract.STATUS_TIMESUP); // set the
																	// status
		computerizedExamFinishProccess();

	}

	public void extandTimeDuration(Long time)
	{
		durationTime  += (time/1000l);	
	}
	
	private class Counter extends Thread {
		public Counter() {
		}
		/**
		 * 
		 * 1000 milliseconds = 1 second
		 * 
		 * 60 seconds = 1 minute
		 * 
		 * 60 * 1000 * durationTime in min (ex.5 min) = 300,000 milliseconds
		 * 
		 * Reduce the thousands place, and you get 300 increments of 1000
		 * milliseconds
		 */

		public void run() {
			
			for (; durationTime >= 0; durationTime--) {
				lblTimer.setText(Long.toString((durationTime/3600l)%24) +":"+ Long.toString((durationTime/60l)%60l) + ":"+ Long.toString(durationTime%60l));
				lblTimer.repaint();
				if (durationTime == 0){
					finishExamByTimer();
						StudentCtrl.examMessage("We are sorry but exam's Time is up!");
				}
				try {
					Thread.sleep(1000);
				}
				catch (InterruptedException e) {
				}

			}

		}

	}

	public void finishExamByLecturer() {
		cptExam.setExamFinishStatus(ExamAbstract.STATUS_LOCKED); // set the status
		StudentCtrl.examMessage("Exam has been locked by lectuer.");
		computerizedExamFinishProccess();
	}
}